#include "BaseThread.h"
#ifdef IS_WINDOWS
  #include <process.h>
#else
  #include <sys/syscall.h>
#endif
#include "Log.h"

namespace dsth {

BaseThread::BaseThread(const SvcFunc& func, const char* name)
    : svc_func_(func), 
    name_( ((name == NULL) ? "unnamed" : name) ),
    running_(false), 
    thread_id_(0),
    thread_handle_(NULL) {
}

BaseThread::BaseThread(const char* name)
    : name_( ((name == NULL) ? "unnamed" : name) ),
    running_(false),
    thread_id_(0),
    thread_handle_(NULL) {
}

BaseThread::BaseThread()
    : name_("unnamed"), 
    running_(false),
    thread_id_(0),
    thread_handle_(NULL) {
}

THD_RET __stdcall BaseThread::ThreadFunc(void* thread) {
    BaseThread* this_thread = reinterpret_cast<BaseThread*>(thread);
    LOG_DEBUG("BaseThread %s is starting.", this_thread->GetName());
    this_thread->thread_id_= BaseThread::GetCurrentThreadId();
    this_thread->svc_func_(this_thread->GetName());
    LOG_DEBUG("BaseThread %s is quiting.", this_thread->GetName());
    this_thread->running_ = false;
    return 0;
}

#ifdef IS_WINDOWS
void BaseThread::Run() {
    running_ = true;
    thread_handle_ = (HANDLE)::_beginthreadex(NULL, 0, &ThreadFunc, this, 0, &thread_id_);
    if (thread_handle_ == NULL) {
        LOG_FATAL("[BaseThread::Run] _beginthreadex failed.\n");
    }
}

void BaseThread::Join() {
    LOG_TRACE("[BaseThread::Join] %s begin", GetName());
    ::WaitForSingleObject(thread_handle_, INFINITE);
    LOG_TRACE("[BaseThread::Join] %s end", GetName());
}

pid_t BaseThread::GetCurrentThreadId() {
    return ::GetCurrentThreadId();
}

#else // POSIX
void BaseThread::Run() {
    running_ = true;
    int err = pthread_create(&thread_handle_, NULL, &ThreadFunc, this);
    if (err != 0) {
        LOG_FATAL("[BaseThread::Run] pthread_create failed.\n");
    }
}

void BaseThread::Join() {
    LOG_TRACE("[BaseThread::Join] %s begin", GetName());
    pthread_join(thread_handle_, NULL);
    LOG_TRACE("[BaseThread::Join] %s end", GetName());
}

pid_t BaseThread::GetCurrentThreadId() {
    return static_cast<pid_t>(::syscall(SYS_gettid));
}
#endif

} // namespace
